﻿/**
 * Copyright (C) 2011 original author and authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using NGuice.Inject.Spi;

namespace NGuice.Inject
{
    /// <summary>
    /// 注入器对象是NGuice的核心，他构建组成你应用程序的对象图。注入器对象跟踪每种类型的依赖并使用bindins
    /// 绑定注入他们。你很少会直接与注入器交互。这种内部的场景是与依赖注入的另一种方式服务定位器模式有所区分的。
    /// 依赖注入包含以下几个默认绑定：
    /// <ul>
    /// <li>注入器本身的实例</li>
    /// <li>对每种类型T的Provider提供者</li>
    /// <li>Injector被创建的Stage</li>
    /// </ul>
    /// 注入器通过使用NGuice这个facade创建。
    /// 注入器也能够InjectMembers(object)在已经构造的实例上进行注入。这能够用于拦截被其他框架或服务创建的对象实例。
    /// 注入器能够调用CreateChildInjector方法创建注入器层次。子注入器继承父注入器的配置（相悖的继承将忽略）。
    /// 注入器的Bindings内部的绑定对内省是有效的，这允许工具和扩展通过反射操作注入器
    /// </summary>
    public interface Injector
    {
        /// <summary>
        /// 注入指定实例的域或方法依赖。忽略存在或不存在的可注入构造器。无论NGuice是否创建一个实例，他都自动执行此
        /// 注入（在第一次执行构造器注入之后），因此如果你能够让NGuice为你创建所有你的对象，你将永远无需使用此方法。
        /// </summary>
        /// <param name="instance">要注入依赖的实例</param>
        /// <see cref="IBinder.GetMembersInjector(Type)">在运行之前进行可选的检查</see>
        void InjectMembers(object instance);

        /// <summary>
        /// 获取用于在T类型对象上注入域或方法依赖的成员注入器
        /// </summary>
        /// <typeparam name="T">要注入成员依赖的类型</typeparam>
        /// <returns></returns>
        IMembersInjector<T> GetMembersInjector<T>();

        /// <summary>
        /// 非泛型方法
        /// </summary>
        /// <param name="genericType"></param>
        /// <returns></returns>
        IMembersInjector GetMembersInjector(Type genericType);

        /// <summary>
        /// 获取注入器的指定类型的显式绑定。返回的字典不包括父注入器的绑定
        /// </summary>
        /// <remarks>如果泛型参数K,I为object，则获取所有</remarks>
        IDictionary<Key<K>, IBinding<I>> GetBindings<K, I>();

        /// <summary>
        /// <seealso cref="GetBindings<K, I>()"/>的非泛型版本，他将返回
        /// 所有的显示绑定。返回的字典不包括父注入器的绑定
        /// 字典的key为Key类型，value为IBinding类型
        /// </summary>
        IDictionary<Key, IBinding> Bindings
        {
            get;
        }

        /// <summary>
        /// 获取注入器的所有指定类型的绑定，包括显式绑定和just-in-time的绑定。返回的字典不包括父注入器的绑定
        /// </summary>
        /// <remarks>如果泛型参数K,I为object，则获取所有</remarks>
        IDictionary<Key<K>, IBinding<I>> GetAllBindings<K, I>();

        /// <summary>
        /// <seealso cref="GetAllBindings<K, I>()"/>的非泛型版本，他将返回
        /// 所有的绑定。包括显式绑定和just-in-time的绑定。返回的字典不包括父注入器的绑定
        /// 字典的key为Key类型，value为IBinding类型
        /// </summary>
        IDictionary<Key, IBinding> AllBindings
        {
            get;
        }

        /// <summary>
        /// 获取给定注入key的绑定。如果key是被一个模块显式的边界绑定则返回显式绑定，否则为
        /// 隐式绑定，隐式绑定将在必要时创建
        /// </summary>
        IBinding GetBinding(Key key);

        /// <summary>
        /// 获取给定类型的绑定。如果key是被一个模块显式的边界绑定则返回显式绑定，否则为
        /// 隐式绑定，隐式绑定将在必要时创建
        /// </summary>
        /// <typeparam name="T">绑定类型</typeparam>
        IBinding<T> GetBinding<T>();

        /// <summary>
        /// 如果绑定存在则获取给定key的绑定，如果不存在则返回null。他与GetBinding<T>(KEY)不同，他并不
        /// 尝试创建just-in-time绑定
        /// </summary>
        IBinding<T> GetExistingBinding<T>(Key<T> key);

        /// <summary>
        /// 获取所有指定类型的显式绑定列表
        /// </summary>
        /// <typeparam name="T">绑定类型</typeparam>
        IList<IBinding<T>> FindBindingsByType<T>();

        /// <summary>
        /// 返回用于为给定注入key获取实例的提供者。如果可能，避免使用此方法，应该首先让NGuice注入你的依赖
        /// </summary>
        /// <exception cref="ConfigurationException">如果注入器无法找到或创建提供者</exception>
        IProvider<T> GetProvider<T>(Key<T> key);

        /// <summary>
        /// 非泛型方法
        /// </summary>
        /// <param name="providerGenericType"></param>
        /// <returns></returns>
        IProvider GetProvider(Type providerGenericType);

        /// <summary>
        /// 为给定的注入key获取合适的实例，这等于<code>GetProvider(key).Get()</code>。如果可能应避免使用
        /// 此方法，应该首先让NGuice注入你的依赖
        /// </summary>
        /// <exception cref="ConfigurationException">如果注入器无法找到或创建提供者</exception>
        /// <exception cref="ProvisionException">当提供一个实例时发生运行时失败异常</exception>
        T GetInstance<T>(Key<T> key);

        /// <summary>
        /// 非泛型版本
        /// </summary>
        /// <param name="clazz"></param>
        /// <returns></returns>
        object GetInstance(Type clazz);

        /// <summary>
        /// 获取父注入器，如果为null则此注入器为顶层注入器
        /// </summary>
        Injector Parent
        {
            get;
        }

        /// <summary>
        /// 获取一个新的注入器，新注入器将继承此注入器的所有声明。所有绑定、scopes、拦截器以及类型转换都将被继承。
        /// 他们都是可见的子注入器。子注入器的元素对此父注入器是不可见的。为此子注入器创建的Just-in-time绑定如果
        /// 可能将在一个祖先注入器中创建。这允许范围化的实例在注入器之间共享。可以使用隐式绑定来阻止在父注入器之间
        /// 共享。子注入器以及他们的祖先都没有key，包括just-in-time绑定。唯一的例外是typeof(Injector)用于每一个注入器
        /// 自身的key
        /// </summary>
        Injector CreateChildInjector<T>(IEnumerable<T> modules) where T : IModule;

        /// <summary>
        /// 获取一个新的注入器，新注入器将继承此注入器的所有声明。所有绑定、scopes、拦截器以及类型转换都将被继承。
        /// 他们都是可见的子注入器。子注入器的元素对此父注入器是不可见的。为此子注入器创建的Just-in-time绑定如果
        /// 可能将在一个祖先注入器中创建。这允许范围化的实例在注入器之间共享。可以使用隐式绑定来阻止在父注入器之间
        /// 共享。子注入器以及他们的祖先都没有key，包括just-in-time绑定。唯一的例外是typeof(Injector)用于每一个注入器
        /// 自身的key
        /// </summary>
        Injector CreateChildInjector(params IModule[] modules);

        /// <summary>
        /// 获取注入器中所有范围的映射，范围的key为Attribute元注释的类型Type，value为scope实例，返回的字典是只读的
        /// </summary>
        IDictionary<Type, IScope> ScopeBindings
        {
            get;
        }

        /// <summary>
        /// 获取包含所有类型转换器绑定的集合。返回的集合是不能修改的
        /// </summary>
        ISet<TypeConverterBinding> TypeConverterBindings
        {
            get;
        }

    }
}
